package org.infodavid.common.impl.services.helpers;

import java.io.Serializable;
import java.util.Collection;

import javax.persistence.PersistenceException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.infodavid.common.impl.services.ServiceUtil;
import org.infodavid.common.model.criteria.IExtendedSearchCriteria;
import org.infodavid.common.persistence.IDataObject;
import org.infodavid.common.persistence.IDataService;
import org.infodavid.common.services.IApplicationContext;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.services.validators.IValidator;

/**
 * The Class ServiceHelper.
 * @param <L> the generic type
 * @param <T> the type of the data managed by the service
 * @param <K> the type of the key of the data
 * @param <C> the generic type
 */
public class ServiceHelper<L extends IDataObject<K>,T extends L,K extends Serializable,C extends IExtendedSearchCriteria> {

	/** The Constant log. */
	private static final Log LOGGER = LogFactory.getLog(ServiceHelper.class);

	/** The data access service. */
	private final IDataService<L,T,K,C> dao;

	/**
	 * The Constructor.
	 * @param dataService the data service
	 */
	public ServiceHelper(final IDataService<L,T,K,C> dataService) {
		if (dataService == null) {
			throw new IllegalArgumentException();
		}

		dao = dataService;
	}

	/**
	 * Creates the.
	 * @return the t
	 * @throws InstantiationException the instantiation exception
	 */
	public T create() throws InstantiationException {
		return dao.create();
	}

	/**
	 * Adds the.
	 * @param context the context
	 * @param value the value
	 * @return the type of the key
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public K add(final IApplicationContext context, final T value) throws PersistenceException,
	    ServiceException {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Adding data: " + value);
		}

		dao.insert(context.getPersistenceSession(), value);

		return value.getKey();
	}

	/**
	 * Gets the.
	 * @param context the context
	 * @param key the key
	 * @return the T
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public T get(final IApplicationContext context, final K key) throws PersistenceException,
	    ServiceException {
		ServiceUtil.validate(context);
		validate(key);

		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Searching data: " + key);
		}

		return dao.findByPrimaryKey(context.getPersistenceSession(), key);
	}

	/**
	 * Removes the.
	 * @param context the context
	 * @param value the object to remove
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public void remove(final IApplicationContext context, final T value) throws PersistenceException,
	    ServiceException {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Removing data: " + value);
		}

		dao.removeEntity(context.getPersistenceSession(), value);
	}

	/**
	 * Removes the.
	 * @param context the context
	 * @param value the object to remove
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public void remove(final IApplicationContext context, final K key) throws PersistenceException,
	    ServiceException {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Removing data using key: " + key);
		}

		dao.remove(context.getPersistenceSession(), key);
	}

	/**
	 * Validate.
	 * @param value the value
	 * @throws ServiceException the service exception
	 */
	public void validate(final T value) throws ServiceException {
		ServiceUtil.validate(value);
	}

	/**
	 * Validate.
	 * @param context the context
	 * @param validator the validator
	 * @param value the value
	 * @throws ServiceException the service exception
	 */
	public void validate(final IApplicationContext context, final IValidator<T> validator,
	    final T value) throws ServiceException {
		ServiceUtil.validate(context);
		validate(value);

		if (validator != null) {
			validator.validate(context, value);
		}
	}

	/**
	 * Validate.
	 * @param context the context
	 * @param validator the validator
	 * @param values the values
	 * @throws ServiceException the service exception
	 */
	public void validate(final IApplicationContext context, final IValidator<T> validator,
	    final Collection<T> values) throws ServiceException {
		ServiceUtil.validate(context);
		ServiceUtil.validate(values);
	}

	/**
	 * Validate.
	 * @param values the values
	 * @throws ServiceException the service exception
	 */
	public void validate(final Collection<? extends L> values) throws ServiceException {
		ServiceUtil.validate(values);
	}

	/**
	 * Validate.
	 * @param key the key
	 * @throws ServiceException the service exception
	 */
	public void validate(final K key) throws ServiceException {
		ServiceUtil.validate(key);
	}

	/**
	 * Update.
	 * @param context the context
	 * @param value the value
	 * @throws PersistenceException the persistence exception
	 * @throws ServiceException the service exception
	 */
	public void update(final IApplicationContext context, final T value) throws PersistenceException,
	    ServiceException {
		if (LOGGER.isDebugEnabled()) {
			LOGGER.debug("Updating data: " + value);
		}

		dao.update(context.getPersistenceSession(), value);
	}

	/**
	 * Gets the data service.
	 * @return the data service
	 */
	public IDataService<L,T,K,C> getDataService() {
		return dao;
	}

	/**
	 * Validate.
	 * @param context the context
	 * @param key the key
	 * @throws ServiceException the service exception
	 */
	public void validate(final IApplicationContext context, final K key) throws ServiceException {
		ServiceUtil.validate(context);
		ServiceUtil.validate(key);
	}
}
